﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace ProgramMain.Framework
{
    //QueueThread base implementation---------------------------------------------------
    //Message Base class
    public class QueueMessageBase
    {
        public int Param { get; private set; }

        public QueueMessageBase()
        {
            Param = 0;
        }

        public QueueMessageBase(int Param)
        {
            this.Param = Param;
        }
    }

    internal class QueueMessager : Control
    {
        public delegate void DelegateMessageMethodType(int Param, QueueMessageBase Message);
        public DelegateMessageMethodType DelegateMessage;

        public QueueMessager()
        {
        }

        public void FireDelegateMessage(QueueMessageBase Message, bool Async)
        {
            if (Async)
            {
                BeginInvoke(DelegateMessage, new Object[] { Message.Param, Message });
            }
            else
            {
                Invoke(DelegateMessage, new Object[] { Message.Param, Message });
            }
        }

        public void FireDelegateMessage(QueueMessageBase Message)
        {
            FireDelegateMessage(Message, true);
        }

        public void FireDelegateMessage(int Param)
        {
            FireDelegateMessage(new QueueMessageBase(Param));
        }
    }

    public class QueueMessageThread : ApplicationContext, IDisposable
    {
        private QueueMessager msg = null;
        protected Control Parent { get; private set; }
        public readonly ThreadPriority ThreadPriority;

        private readonly ManualResetEvent startEvent;
        private readonly ManualResetEvent stopEvent;

        public QueueMessageThread(Control Parent, ThreadPriority ThreadPriority)
        {
            this.Parent = Parent;
            this.ThreadPriority = ThreadPriority;

            startEvent = new ManualResetEvent(false);
            stopEvent = new ManualResetEvent(false);
        }

        public new void Dispose()
        {
            ExitThread();
            base.Dispose();
        }

        #region QueueThread functions
        public void CreateThread()
        {
            ExitThread();

            ThreadStart threadDeligate = new ThreadStart(QueueThread);
            Thread thread = new Thread(threadDeligate);

            thread.Priority = ThreadPriority;
            thread.SetApartmentState(ApartmentState.STA);

            startEvent.Reset();
            stopEvent.Reset();

            thread.Start();

            startEvent.WaitOne();
        }

        public new void ExitThread()
        {
            if (startEvent.WaitOne(0))
            {
                base.ExitThread();

                stopEvent.WaitOne();

                msg = null;
            }
        }

        private void QueueThread()
        {
            msg = new QueueMessager();
            IntPtr hwnd = msg.Handle;
            if (hwnd != IntPtr.Zero)
            {
                msg.DelegateMessage += new QueueMessager.DelegateMessageMethodType(OnDelegateMessage);

                startEvent.Set();

                OnThreadStart();

                Application.Run(this);

                OnThreadStop();

                stopEvent.Set();
            }
        }
        #endregion

        #region Send Message to QueueThreadFunctions
        protected void PostMessage(int Param)
        {
            if (msg != null)
            {
                msg.FireDelegateMessage(Param);
            }
        }

        protected void PostMessage(QueueMessageBase Message)
        {
            if (msg != null)
            {
                msg.FireDelegateMessage(Message);
            }
        }

        protected void SendMessage(int Param)
        {
            if (msg != null)
            {
                msg.FireDelegateMessage(new QueueMessageBase(Param), false);
            }
        }

        protected void SendMessage(QueueMessageBase Message)
        {
            if (msg != null)
            {
                msg.FireDelegateMessage(Message, false);
            }
        }

        private void OnDelegateMessage(int Param, QueueMessageBase Message)
        {
            TranslateMessage(Param, Message);
        }
        #endregion

        //method to translate messages in QueueThread
        protected virtual bool TranslateMessage(int Param, QueueMessageBase Message)
        {
            return false;
        }

        protected virtual void OnThreadStart()
        {
        }

        protected virtual void OnThreadStop()
        {
        }
    }
}
